<?php
class Util {
    
    /**
     * 重复调用（缓存于本次请求的内存中）
     * 用法同call_user_func_array()
     * 参数$useCache默认使用本次请求中的结果缓存
     */
    public function recall($callback, $param_arr, $useCache = true){
        $key = 'recall_ret_' . sha1( ( is_array($callback) ? get_class($callback[0]).$callback[1] : json_encode($callback) ) . serialize($param_arr) );
        $cache = $useCache ? $GLOBALS[$key] : false;
        if ($cache) return $cache;
        $ret = call_user_func_array($callback, $param_arr);
        $GLOBALS[$key] = $ret;
        return $ret;
    }
    
    /**
     * 带有缓存的调用（缓存于全局）
     * 仅适用于返回值一直依赖参数变化的方法
     */
    public function callCache($callback, $param_arr, $mmcKey = false, $expire = 600){
        $trace = debug_backtrace();
        static $mmc = null;
        $mmc = $mmc ?: obj('dwCache', array($GLOBALS['app_id']), '', true); //确保使用与外界不同的实例，但防止此作用域重复生成实例
        false !== $mmcKey || $mmcKey = 'callcache_ret_' . sha1( ( is_array($callback) ? get_class($callback[0]).$callback[1] : json_encode($callback) ) . serialize($param_arr) . $trace[1]['file'].$trace[1]['line'] );
        $cache = $mmc->get($mmcKey);
        if ($cache && CACHE_GET_ABLE) return $cache;
        $ret = call_user_func_array($callback, $param_arr);
        if (CACHE_SET_ABLE) $mmc->set($mmcKey, $ret, $expire);
        return $ret;
    }
    
    /**
     * 带有缓存的调用（缓存于全局）
     * 仅适用于返回值一直依赖参数变化的方法
     */
    public function callRedis($callback, $param_arr, $redisKey = false, $expire = 600){
        $trace = debug_backtrace();
        static $redis = null;
        $redis = $redis ?: obj('dwRedis');
        false !== $redisKey || $redisKey = 'callredis_ret_' . sha1( ( is_array($callback) ? get_class($callback[0]).$callback[1] : json_encode($callback) ) . serialize($param_arr) . $trace[1]['file'].$trace[1]['line'] );
        $cache = $redis->get($redisKey);
        if ($cache && CACHE_GET_ABLE) return unserialize($cache);
        $ret = call_user_func_array($callback, $param_arr);
        if (CACHE_SET_ABLE) $redis->set($redisKey, serialize($ret), $expire);
        return $ret;
    }
    
    /**
     * 用打乱顺序、随机长度的ASCII码字符串来生成随机字符串
     */
    public function buildRandStr(){
        $str = '';
        $len = mt_rand(10, 255);
        for ($i = 0; $i < $len; $i ++) {
            $str .= chr(mt_rand(0, 255));
        }
        return sha1($str);
    }
    
    //格式化显示debug trace
    public function showTrace($errMsg = '', $goDie = true) {
        $trace = debug_backtrace();
        $out = "<hr/><div>".$errMsg."<br /><table border='1'>";
        $out .= "<thead><tr><th>file</th><th>line</th><th>function</th><th>args</th></tr></thead>";
        foreach ($trace as $v) {
            if (!isset($v['file'])) $v['file'] = '[PHP Kernel]';
            if (!isset($v['line'])) $v['line'] = '';
            $v['args'] = print_r($v['args'], true);
            $out .= "<tr><td>{$v["file"]}</td><td>{$v["line"]}</td><td>{$v["function"]}</td><td>{$v["args"]}</td></tr>";
        }
        $out .= "</table></div><hr/></p>";
        echo $out;
        $goDie AND die();
    }
    
}